package org.tradeinterceptor.modular.strategy.modules;

import org.tradeinterceptor.modular.strategy.ForexSignal;
import org.tradeinterceptor.modular.strategy.StrategyModule;

import com.riflexo.charting.api.AbstractEasyCalculator;
import com.riflexo.charting.api.Item;

public class HeikinAshiStrategyModule implements StrategyModule {

	private AbstractEasyCalculator parent;
	private boolean inPosition = false;
	private ForexSignal positionDirection = ForexSignal.NONE;
	
	private int dojiCounter = 0;
	private int maxDojiCounter = 2;
	
	
	@Override
	public ForexSignal getSignal() {
		HeikinAshi ha = calculateHA(parent.getMainSeries().getDataItem(),parent.getMainSeries().getDataItem(1));
		
		ForexSignal signal = ForexSignal.NONE;
		if(inPosition){
			if(((positionDirection == ForexSignal.BUY) && (isBear(ha))) || ((positionDirection == ForexSignal.SELL) && (isBull(ha)))){
				signal = ForexSignal.CLOSE;
			} else if(isDoji(ha)){
				dojiCounter ++;
				if(dojiCounter == maxDojiCounter){
					signal = ForexSignal.CLOSE;
				}
			}
		}else{
			if(isBull(ha)){
				signal = ForexSignal.BUY;
			} else if(isBear(ha)){
				signal = ForexSignal.SELL;
			}
		}
		
		return signal;
	}
	
	@Override
	public void setPosition(ForexSignal signal) {
		inPosition = true;
		positionDirection = signal;
	}
	

	@Override
	public void close() {
		inPosition = false;
		dojiCounter = 0;
	}

	@Override
	public void declare(AbstractEasyCalculator parent) {
		// TODO Auto-generated method stub
		this.parent = parent;
	}
	
	private boolean isDoji(HeikinAshi ha){
		boolean retVal = false;
		if((ha.getBody() * 3 < ha.getLowerTail()) && (ha.getBody() * 3 < ha.getUpperTail())){
			retVal = true;
		}
		return retVal;
	}
	
	private boolean isBull(HeikinAshi ha){
		boolean retVal = false;
		if((ha.getBody() > ha.getLowerTail() * 5) && (ha.getUpperTail() > ha.getLowerTail() * 3) && (ha.getClose() > ha.getOpen())){
			retVal = true;
		}
		return retVal;
	}
	
	private boolean isBear(HeikinAshi ha){
		boolean retVal = false;
		if((ha.getBody() > ha.getUpperTail() * 5) && (ha.getLowerTail() > ha.getUpperTail() * 3) && (ha.getOpen() > ha.getClose())){
			retVal = true;
		}
		return retVal;
	}
	
	private HeikinAshi calculateHA(Item current, Item previous){
		HeikinAshi ha = new HeikinAshi();
		ha.setClose((current.getOpen()+current.getHigh()+current.getLow()+current.getClose())/4);
		ha.setOpen((previous.getOpen() + previous.getClose())/2);
		ha.setHigh(Math.max(current.getClose(),Math.max(current.getHigh(), current.getOpen())));
		ha.setLow(Math.min(current.getClose(),Math.min(current.getLow(), current.getOpen())));
		return ha;
	}
	
	private class HeikinAshi{
		double open;
		double close;
		double high;
		double low;
		public double getOpen() {
			return open;
		}
		public void setOpen(double open) {
			this.open = open;
		}
		public double getClose() {
			return close;
		}
		public void setClose(double close) {
			this.close = close;
		}
		public double getHigh() {
			return high;
		}
		public void setHigh(double high) {
			this.high = high;
		}
		public double getLow() {
			return low;
		}
		public void setLow(double low) {
			this.low = low;
		}
		
		public double getBody(){
			return Math.abs(getOpen() - getClose());
		}
		
		public double getLowerTail(){
			return Math.min(getOpen(), getClose()) - getLow();
		}
		
		public double getUpperTail(){
			return getHigh() - Math.max(getOpen(), getClose());
		}
		
	}

}
